package com.java.simple.smallspring.context.event;

import com.java.simple.smallspring.beans.BeansException;
import com.java.simple.smallspring.beans.factory.BeanFactory;
import com.java.simple.smallspring.beans.factory.BeanFactoryAware;
import com.java.simple.smallspring.context.ApplicationEvent;
import com.java.simple.smallspring.context.ApplicationListener;
import com.java.simple.smallspring.util.ClassUtil;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * @author zhoujunlin
 * @date 2022年08月31日 16:06
 * @desc
 */
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();
    private BeanFactory beanFactory;

    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    protected Collection<ApplicationListener> getApplicationListener(ApplicationEvent event) {
        LinkedList<ApplicationListener> allApplicationListeners = new LinkedList<>();
        for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
            if (supportEvent(applicationListener, event)) {
                allApplicationListeners.add(applicationListener);
            }
        }
        return allApplicationListeners;
    }

    /**
     * 监听器是否堆该时间感兴趣
     *
     * @param applicationListener
     * @param event
     * @return
     */
    protected boolean supportEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
        // debug this method
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();

        Class<?> targetClass = ClassUtil.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClass;
        try {
            eventClass = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("Wrong event class name:" + className);
        }
        // 判定eventClassName对象所表示的类或接口与指定的event.getClass()参数所表示的类或接口是否相同 或是否有其超类或超接口
        // isAssignableFrom是用来判断子类和父类的关系的 或者接口的实现类和接口的关系的 默认所有的类的终极父类都是Object
        //    如果A.isAssignableFrom(B)是true 证明B可以转换为A 也就是A可以由B转换而来
        return eventClass.isAssignableFrom(event.getClass());
    }


}
